package stud.mpgame.snapshot;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class SnapshotManager {

    private int tickTime; //время между двумя снэпшотами
    private int snapshotsLength; //сколько объект может хранить снэпшотов
    private List < SnapshotCommands > snapshots; 
    
    private int earliestCommandTime;
    
    public SnapshotManager(int tickTime, int snapshotsLength) {
    	snapshots = Collections.synchronizedList(new ArrayList < SnapshotCommands >());
    	this.tickTime = tickTime;
    	this.snapshotsLength = snapshotsLength;
    	earliestCommandTime = Integer.MAX_VALUE;
    }
    
    public void setInitialSnapshot (ISnapshot ss, int pos) {
     	snapshots.clear();
     	for(int i = 0; i < pos; ++i) {
     		snapshots.add(null);
     	}
    	snapshots.add(new SnapshotCommands(ss));
    	for(int i = pos + 1; i < snapshotsLength; ++i) {
     		snapshots.add(snapshots.get(i - 1).modelNext(tickTime));
     	}
    }

    public void addCommand (ICommand cmd) {
    	earliestCommandTime = Math.min(earliestCommandTime, cmd.getTime());
    	int firstNotNullPosition = 0;
    	while (snapshots.get(firstNotNullPosition) == null)
            firstNotNullPosition++;
    	int timesDiff = cmd.getTime() - snapshots.get(firstNotNullPosition).getSnapshot().getTime();
    	if(timesDiff >= 0) {
    		int snapshotIndex = firstNotNullPosition + timesDiff  / tickTime;
    		if (snapshotIndex < snapshots.size()) {
    			snapshots.get(snapshotIndex).getCommands().add(cmd);
    		}
    	}
    }

    public void addCommands (List < ICommand > list) {
        for (ICommand cmd: list) {
        	addCommand(cmd);
        }
    }

    public ISnapshot getSnapshot (int time) {
    	for (SnapshotCommands sc: snapshots) {
    		if (sc != null && sc.getSnapshot().getTime() >= time) {
    			return sc.getSnapshot();
    		}
    	}
    	return snapshots.get(snapshots.size() - 1).getSnapshot();
    }

    public String toString() {
    	String s = "";
    	for(int i = 0; i < snapshots.size(); ++i) {
    		String q = snapshots.get(i) != null ? snapshots.get(i).getSnapshot() + "" : null;
    		s += i + ": " + q + "\n";
    		if(snapshots.get(i) != null && snapshots.get(i).getCommands() != null) {
    			if(snapshots.get(i).getCommands().size() != 0) s += "COMMANDS: ";
    			for(int j = 0; j < snapshots.get(i).getCommands().size(); ++j) {
    				s += snapshots.get(i).getCommands().get(j) + " ";
    			}
    		}
    	}
    	return s + "\n";
    }
    
    public void update (int deltaTime) {
    	int currentIndexPosition = -1;
    	while (snapshots.get(++currentIndexPosition) == null);
    	while (currentIndexPosition < snapshots.size() && snapshots.get(currentIndexPosition++).getSnapshot().getTime() < earliestCommandTime - tickTime);
    	if (currentIndexPosition >= snapshots.size()) {
    		currentIndexPosition = snapshotsLength - 1;
    	}
    	int quantity = deltaTime / tickTime;
    	for (int i = currentIndexPosition - 1; i < snapshots.size() - 1; i++) {
    		snapshots.set(i + 1, snapshots.get(i).modelNext(tickTime, snapshots.get(i + 1).getCommands()));
        }
    	int n = snapshots.size();
    	for (int i = n - 1; i < n + quantity - 1; i++) {
    		snapshots.add(i + 1, snapshots.get(i).modelNext(tickTime));
        }
    	for(int i = 0; i < quantity; ++i) {
    		snapshots.remove(0);
        }
    	earliestCommandTime = Integer.MAX_VALUE;
    }
}
